package com.hs.communication.common.message;

import com.hs.communication.common.enums.Device;
import com.hs.communication.common.fallback.handlers.ChargerHandler;
import com.hs.communication.common.fallback.handlers.InverterHandler;
import com.hs.communication.common.fallback.handlers.UpsHandler;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import java.util.HashMap;
import java.util.Map;
import java.util.function.BiConsumer;

/**
 * 消息处理器
 */
@Component
public class MessageHandler {
    /**
     * @param connection 连接方式,mqtt还是socket
     * @param bytes
     */
    public void resolveBytes(String connection, byte[] bytes) {
//        //去除crc,保留数据
//        byte[] data = Arrays.copyOfRange(bytes, 0, bytes.length - 2);
//        byte[] crc = Arrays.copyOfRange(bytes, bytes.length - 2, bytes.length);
//
//        byte[] crc_calc = CrcUtil.crc16(data);
//
//        if (!CrcUtil.isCrcOk(crc, crc_calc)) {
//            System.out.println("crc校验不过");
//            return;
//        }

        resolveByByte(connection, bytes);
    }

    /**
     * 假设一帧协议格式如下
     * 帧头   设备类型 功能码 帧码   数据长度 数据内容 crc校验
     * 0x10  1字节   1字节  2字节  2字节    n字节   2字节
     * 其中
     * * 设备类型: UPS 充电桩 逆变器等
     * * <p>
     * * 功能码,假设0x01代表实时数据,0x03代表参数设置
     * * 帧码: 同一帧数据第几次发送,每次累加
     * * 数据长度: 数据内容的字节数
     * * crc校验采用大端序,数据内容里面的可以选择
     *
     * @param data
     */
    public void resolveByByte(String connection, byte[] data) {
        BiConsumer<String, byte[]> consumer = map.get(Device.fromValue(data[1]));
        consumer.accept(connection, data);
    }

    /**
     * 设计说明:
     * 首先有一个map,判断是什么设备,
     * 根据不同设备执行不同逻辑
     * 再接着在具体的设备处理类里面还有一个map,
     * 这个map处理具体的帧,假设0x01帧表示实时信息,就执行对应的函数逻辑
     * <p>
     * 两层map的设计功能等价于
     * if(device == ups) {
     * if(function_code == 0x01) {
     * handle0x01()
     * } else if(function_code == 0x02) {
     * handle0x02()
     * }
     * ...
     * } else if(device == config) {
     * ...
     * }
     * ...
     * <p>
     * 为什么这么设计?
     * 可扩展,好维护
     */
    private Map<Device, BiConsumer<String, byte[]>> map = new HashMap<>();

    @PostConstruct
    public void init() {
        map.put(Device.CHARGER, this::handleCharger);
        map.put(Device.UPS, this::handleUps);
        map.put(Device.INVERTER, this::handleInverter);
    }

    @Resource
    private UpsHandler upsHandler;

    @Resource
    private ChargerHandler chargerHandler;

    @Resource
    private InverterHandler inverterHandler;

    public void handleUps(String connection, byte[] bytes) {
        BiConsumer<String, byte[]> consumer = upsHandler.map.get(bytes[2]);
        consumer.accept(connection, bytes);
    }

    public void handleCharger(String connection, byte[] bytes) {
        BiConsumer<String, byte[]> consumer = chargerHandler.map.get(bytes[2]);
        consumer.accept(connection, bytes);
    }

    public void handleInverter(String connection, byte[] bytes) {
        BiConsumer<String, byte[]> consumer = inverterHandler.map.get(bytes[2]);
        consumer.accept(connection, bytes);
    }

}
